package luke.audio.processor;

/**
 * 鼓点音效生成器
 * 生成各种类型的鼓点音效PCM数据
 */
public class BeatSoundGenerator {
    
    // 音频参数
    private static final int SAMPLE_RATE = 44100; // 采样率
    private static final int CHANNELS = 2;        // 声道数（立体声）
    private static final int BYTES_PER_SAMPLE = 2; // 每个样本的字节数（16位）

    /**
     * 生成快板声音样本
     *
     * @return 快板声音的字节数组
     */
    public static byte[] generateBeatSound() {
        // 快板持续时间（毫秒）- 短促但有力的"嚓"声
        int beatDurationMs = 35; // 增加持续时间以增强感知

        // 计算快板样本数
        int sampleCount = (int) (SAMPLE_RATE * beatDurationMs / 1000.0);

        // 每个样本4字节（16位 * 2声道）
        byte[] soundData = new byte[sampleCount * BYTES_PER_SAMPLE * CHANNELS];

        // 生成"嚓"快板波形
        for (int i = 0; i < sampleCount; i++) {
            // 计算时间（秒）
            double time = (double) i / SAMPLE_RATE;

            // 使用高频白噪声来模拟"嚓"声，增加振幅
            double noise = (Math.random() * 2 - 1) * 1; // 从0.7增加到0.9

            // 应用快速但不过分衰减的包络，使声音更有力
            double envelope = Math.exp(-time * 180); // 从120减少到80，减缓衰减

            // 添加更强的高频成分增强清脆感
            double highFreq1 = Math.sin(2 * Math.PI * 2000 * time) * 0.8 * envelope;   // 从0.35增加到0.5
            double highFreq2 = Math.sin(2 * Math.PI * 6000 * time) * 0.7 * envelope;   // 从0.3增加到0.4
            double highFreq3 = Math.sin(2 * Math.PI * 8000 * time) * 0.5 * envelope; // 从0.25增加到0.35

            // 组合噪声和高频成分，增加总体增益
            double combined = (noise * envelope + highFreq1 + highFreq2 + highFreq3) * 1.6; // 增加1.3倍总体增益

            // 限制在有效范围内
            if (combined > 1.0) combined = 1.0;
            if (combined < -1.0) combined = -1.0;

            // 生成左右声道的样本值（相同值，创建单声道效果）
            short sampleValue = (short) (combined * Short.MAX_VALUE);

            // 限制样本值范围
            if (sampleValue > Short.MAX_VALUE) sampleValue = Short.MAX_VALUE;
            if (sampleValue < Short.MIN_VALUE) sampleValue = Short.MIN_VALUE;

            // 将short值转换为字节（小端序）
            // 左声道 (i*4 和 i*4+1)
            soundData[i * 4] = (byte) (sampleValue & 0xFF);
            soundData[i * 4 + 1] = (byte) ((sampleValue >> 8) & 0xFF);
            // 右声道 (i*4+2 和 i*4+3)
            soundData[i * 4 + 2] = (byte) (sampleValue & 0xFF);
            soundData[i * 4 + 3] = (byte) ((sampleValue >> 8) & 0xFF);
        }

        return soundData;
    }

    /**
     * 生成气泡声音样本
     *
     * @return 气泡声音的字节数组
     */
    public static byte[] generateBubbleSound() {
        // 气泡声持续时间（毫秒）
        int bubbleDurationMs = 50;

        // 计算样本数
        int sampleCount = (int) (SAMPLE_RATE * bubbleDurationMs / 1000.0);

        // 每个样本4字节（16位 * 2声道）
        byte[] soundData = new byte[sampleCount * BYTES_PER_SAMPLE * CHANNELS];

        // 生成气泡声音波形
        for (int i = 0; i < sampleCount; i++) {
            // 计算时间（秒）
            double time = (double) i / SAMPLE_RATE;

            // 使用正弦波创建气泡声基础频率
            double frequency = 800 + 400 * Math.sin(2 * Math.PI * 5 * time); // 800Hz基础频率，带有5Hz的调制
            double wave = Math.sin(2 * Math.PI * frequency * time);

            // 应用包络线，创建气泡破裂的效果
            double envelope = Math.exp(-time * 20) * (1 - time / (bubbleDurationMs / 1000.0));

            // 添加一些高频成分增强气泡感
            double highFreq = Math.sin(2 * Math.PI * 2000 * time) * 0.3 * envelope;

            // 添加轻微的随机噪声使声音更自然
            double noise = (Math.random() * 2 - 1) * 0.1 * envelope;

            // 组合波形
            double combined = wave * envelope + highFreq + noise;

            // 限制在有效范围内
            if (combined > 1.0) combined = 1.0;
            if (combined < -1.0) combined = -1.0;

            // 生成左右声道的样本值（略有差异创建立体声效果）
            short leftSampleValue = (short) (combined * Short.MAX_VALUE * 0.9); // 左声道稍微弱一些
            short rightSampleValue = (short) (combined * Short.MAX_VALUE); // 右声道稍强

            // 限制样本值范围
            if (leftSampleValue > Short.MAX_VALUE) leftSampleValue = Short.MAX_VALUE;
            if (leftSampleValue < Short.MIN_VALUE) leftSampleValue = Short.MIN_VALUE;
            if (rightSampleValue > Short.MAX_VALUE) rightSampleValue = Short.MAX_VALUE;
            if (rightSampleValue < Short.MIN_VALUE) rightSampleValue = Short.MIN_VALUE;

            // 将short值转换为字节（小端序）
            // 左声道 (i*4 和 i*4+1)
            soundData[i * 4] = (byte) (leftSampleValue & 0xFF);
            soundData[i * 4 + 1] = (byte) ((leftSampleValue >> 8) & 0xFF);
            // 右声道 (i*4+2 和 i*4+3)
            soundData[i * 4 + 2] = (byte) (rightSampleValue & 0xFF);
            soundData[i * 4 + 3] = (byte) ((rightSampleValue >> 8) & 0xFF);
        }

        return soundData;
    }

    /**
     * 生成鼓声音样本
     *
     * @return 鼓声音的字节数组
     */
    public static byte[] generateDrumSound() {
        // 鼓声持续时间（毫秒）- 更接近真实鼓声的持续时间
        int drumDurationMs = 400; // 从200增加到300毫秒，使声音更饱满

        // 计算样本数
        int sampleCount = (int) (SAMPLE_RATE * drumDurationMs / 1000.0);

        // 每个样本4字节（16位 * 2声道）
        byte[] soundData = new byte[sampleCount * BYTES_PER_SAMPLE * CHANNELS];

        // 生成鼓声音波形
        for (int i = 0; i < sampleCount; i++) {
            // 计算时间（秒）
            double time = (double) i / SAMPLE_RATE;

            // 生成底鼓特有的低频正弦波（更低的频率，更接近真实底鼓）
            double lowFreq = Math.sin(2 * Math.PI * 30 * time) * 1.2; // 从60Hz降到50Hz，增强低频，振幅从0.7增加到0.8
            double lowFreq1 = Math.sin(2 * Math.PI * 50 * time) * 1.6; // 从60Hz降到50Hz，增强低频，振幅从0.7增加到0.8

            // 生成军鼓特有的中频噪声（增加响弦效果）
            double noise = (Math.random() * 2 - 1) * 0.4; // 从0.3增加到0.4，增强军鼓的"沙沙"声

            // 生成更丰富的高频成分（增加鼓声的明亮感）
            double highFreq = Math.sin(2 * Math.PI * 2500 * time) * 0.5; // 从2000Hz增加到2500Hz，振幅从0.2增加到0.3
            double highFreq2 = Math.sin(2 * Math.PI * 4000 * time) * 0.1; // 从3000Hz增加到4000Hz，振幅从0.1增加到0.2

            // 添加额外的高频成分增强打击感
            double highFreq3 = Math.sin(2 * Math.PI * 6000 * time) * 0.1; // 新增6000Hz成分

            // 应用更真实的鼓声包络线，创建鼓声的冲击和衰减效果
            double envelope;
            if (time < 0.005) {
                // 更快的上升时间，模拟鼓棒击打的瞬间冲击
                envelope = time / 0.005;
            } else {
                // 更自然的衰减曲线，模拟鼓声的自然衰减
                envelope = Math.exp(-(time - 0.005) * 20); // 从30降到20，减缓衰减速度
            }

            // 组合所有成分，增强整体音量
            double combined = (lowFreq1+lowFreq + noise + highFreq + highFreq2 + highFreq3) * envelope * 1.8; // 增加1.2倍总体增益

            // 限制在有效范围内
            if (combined > 1.0) combined = 1.0;
            if (combined < -1.0) combined = -1.0;

            // 生成左右声道的样本值（相同值，创建单声道效果）
            short sampleValue = (short) (combined * Short.MAX_VALUE);

            // 限制样本值范围
            if (sampleValue > Short.MAX_VALUE) sampleValue = Short.MAX_VALUE;
            if (sampleValue < Short.MIN_VALUE) sampleValue = Short.MIN_VALUE;

            // 将short值转换为字节（小端序）
            // 左声道 (i*4 和 i*4+1)
            soundData[i * 4] = (byte) (sampleValue & 0xFF);
            soundData[i * 4 + 1] = (byte) ((sampleValue >> 8) & 0xFF);
            // 右声道 (i*4+2 和 i*4+3)
            soundData[i * 4 + 2] = (byte) (sampleValue & 0xFF);
            soundData[i * 4 + 3] = (byte) ((sampleValue >> 8) & 0xFF);
        }

        return soundData;
    }

    /**
     * 生成三角铁声音样本
     *
     * @return 三角铁声音的字节数组
     */
    public static byte[] generateTriangleSound() {
        // 三角铁声持续时间（毫秒）- 清脆但有一定延音的声音
        int glassDurationMs = 200;

        // 计算样本数
        int sampleCount = (int) (SAMPLE_RATE * glassDurationMs / 1000.0);

        // 每个样本4字节（16位 * 2声道）
        byte[] soundData = new byte[sampleCount * BYTES_PER_SAMPLE * CHANNELS];

        // 生成三角铁声音波形
        for (int i = 0; i < sampleCount; i++) {
            // 计算时间（秒）
            double time = (double) i / SAMPLE_RATE;

            // 生成基础频率（以C5为例，5000.25Hz，三角铁的典型频率）
            double fundamentalFreq = 5000.25;
            
            // 移除基础频率，只保留泛音和高频成分来创造更清脆的声音
            double fundamental = 0; // Math.sin(2 * Math.PI * fundamentalFreq * time);

            // 生成泛音（三角铁的共振特性），增强高频泛音
            double harmonic2 = 0.8 * Math.sin(2 * Math.PI * fundamentalFreq * 1.5 * time);  // 1.5倍频
            double harmonic3 = 0.7 * Math.sin(2 * Math.PI * fundamentalFreq * 2.0 * time);  // 2倍频
            double harmonic4 = 0.6 * Math.sin(2 * Math.PI * fundamentalFreq * 2.5 * time);  // 2.5倍频
            double harmonic5 = 0.5 * Math.sin(2 * Math.PI * fundamentalFreq * 3.0 * time);  // 3倍频

            // 添加更多高频成分增强清脆感
            double highFreq1 = 0.4 * Math.sin(2 * Math.PI * 6000 * time);
            double highFreq2 = 0.3 * Math.sin(2 * Math.PI * 8000 * time);
            double highFreq3 = 0.25 * Math.sin(2 * Math.PI * 10000 * time);
            double highFreq4 = 0.2 * Math.sin(2 * Math.PI * 12000 * time);

            // 添加一些随机噪声来模拟敲击的不规则性
            double noise = (Math.random() * 2 - 1) * 0.15;

            // 组合所有成分，移除基础频率以创造更清脆的声音
            double combinedWave = fundamental + harmonic2 + harmonic3 + harmonic4 + harmonic5 + 
                                  highFreq1 + highFreq2 + highFreq3 + highFreq4 + noise;

            // 应用三角铁特有的包络线（快速上升，然后中等速度衰减）
            double envelope;
            if (time < 0.001) {
                // Attack阶段：更快速上升
                envelope = time / 0.001;
            } else {
                // Decay阶段：中等速度衰减（模拟三角铁的延音特性）
                envelope = Math.exp(-(time - 0.001) * 15);
            }

            // 组合波形和包络
            double finalSound = combinedWave * envelope;

            // 限制在有效范围内
            if (finalSound > 1.0) finalSound = 1.0;
            if (finalSound < -1.0) finalSound = -1.0;

            // 生成左右声道的样本值（相同值，创建单声道效果）
            short sampleValue = (short) (finalSound * Short.MAX_VALUE);

            // 限制样本值范围
            if (sampleValue > Short.MAX_VALUE) sampleValue = Short.MAX_VALUE;
            if (sampleValue < Short.MIN_VALUE) sampleValue = Short.MIN_VALUE;

            // 将short值转换为字节（小端序）
            // 左声道 (i*4 和 i*4+1)
            soundData[i * 4] = (byte) (sampleValue & 0xFF);
            soundData[i * 4 + 1] = (byte) ((sampleValue >> 8) & 0xFF);
            // 右声道 (i*4+2 和 i*4+3)
            soundData[i * 4 + 2] = (byte) (sampleValue & 0xFF);
            soundData[i * 4 + 3] = (byte) ((sampleValue >> 8) & 0xFF);
        }

        return soundData;
    }

    /**
     * 生成木鱼声音样本
     *
     * @return 木鱼声音的字节数组
     */
    public static byte[] generateWoodenFishSound() {
        // 木鱼声持续时间（毫秒）- 短促而清晰
        int woodenFishDurationMs = 120;

        // 计算样本数
        int sampleCount = (int) (SAMPLE_RATE * woodenFishDurationMs / 1000.0);

        // 每个样本4字节（16位 * 2声道）
        byte[] soundData = new byte[sampleCount * BYTES_PER_SAMPLE * CHANNELS];

        // 生成木鱼声音波形
        for (int i = 0; i < sampleCount; i++) {
            // 计算时间（秒）
            double time = (double) i / SAMPLE_RATE;

            // 生成基础频率（以G4为例，392Hz，木鱼的典型频率）
            double fundamentalFreq = 500.0;
            double fundamental = Math.sin(2 * Math.PI * fundamentalFreq * time);

            // 生成较低的谐波成分（木鱼的木质感）
            double harmonic2 = 0.5 * Math.sin(2 * Math.PI * fundamentalFreq * 0.5 * time); // 1/2频
            double harmonic3 = 0.3 * Math.sin(2 * Math.PI * fundamentalFreq * 0.75 * time); // 3/4频

            // 添加一些随机噪声来模拟木质敲击的不规则性
            double noise = (Math.random() * 2 - 1) * 0.2;

            // 组合所有成分
            double combined = fundamental + harmonic2 + harmonic3 + noise;

            // 应用木鱼特有的包络线（快速上升然后快速衰减）
            double envelope;
            if (time < 0.0005) {
                // Attack阶段：极快上升
                envelope = time / 0.0005;
            } else {
                // Decay阶段：快速衰减
                envelope = Math.exp(-(time - 0.0005) * 30);
            }

            // 组合波形和包络
            double finalSound = combined * envelope;

            // 限制在有效范围内
            if (finalSound > 1.0) finalSound = 1.0;
            if (finalSound < -1.0) finalSound = -1.0;

            // 生成左右声道的样本值（相同值，创建单声道效果）
            short sampleValue = (short) (finalSound * Short.MAX_VALUE);

            // 限制样本值范围
            if (sampleValue > Short.MAX_VALUE) sampleValue = Short.MAX_VALUE;
            if (sampleValue < Short.MIN_VALUE) sampleValue = Short.MIN_VALUE;

            // 将short值转换为字节（小端序）
            // 左声道 (i*4 和 i*4+1)
            soundData[i * 4] = (byte) (sampleValue & 0xFF);
            soundData[i * 4 + 1] = (byte) ((sampleValue >> 8) & 0xFF);
            // 右声道 (i*4+2 和 i*4+3)
            soundData[i * 4 + 2] = (byte) (sampleValue & 0xFF);
            soundData[i * 4 + 3] = (byte) ((sampleValue >> 8) & 0xFF);
        }

        return soundData;
    }

    /**
     * 生成挥剑声音样本
     *
     * @return 挥剑声音的字节数组
     */
    public static byte[] generateSwordSound() {
        // 挥剑声持续时间（毫秒）- 包含挥舞和击打声的完整声音
        int swordDurationMs = 250; // 根据您的要求从150改为250

        // 计算样本数
        int sampleCount = (int) (SAMPLE_RATE * swordDurationMs / 1000.0);

        // 每个样本4字节（16位 * 2声道）
        byte[] soundData = new byte[sampleCount * BYTES_PER_SAMPLE * CHANNELS];

        // 生成挥剑声音波形
        for (int i = 0; i < sampleCount; i++) {
            // 计算时间（秒）
            double time = (double) i / SAMPLE_RATE;

            // 生成挥剑的低频成分（"呼呼"声）
            double lowFreq = Math.sin(2 * Math.PI * 8000 * time) * 0.4; 

            // 生成挥剑的中频成分（"嗖嗖"声）
            double midFreq = Math.sin(2 * Math.PI * 200 * time) * 0.3; 

            // 生成挥剑击打的高频成分（"锵"声）
            double highFreq = Math.sin(2 * Math.PI * 6000 * time) * 0.5; 

            // 添加高频噪声模拟挥剑击打的尖锐感
            double noise = (Math.random() * 2 - 1) * 0.4;

            // 添加额外的高频成分增强挥剑的清脆感
            double highFreq2 = Math.sin(2 * Math.PI * 17000 * time) * 0.3; 

            // 应用挥剑特有的包络线
            double envelope;
            if (time < 0.02) {
                // Attack阶段：快速上升模拟挥舞动作
                envelope = time / 0.02;
            } else if (time < 0.05) {
                // 短暂的平台期模拟挥舞到击打点
                envelope = 1.0;
            } else {
                // Decay阶段：快速衰减模拟声音消散
                envelope = Math.exp(-(time - 0.05) * 40);
            }

            // 在声音的后期添加一个尖锐的击打声
            double strikeEnvelope = 0.0;
            if (time > 0.04 && time < 0.08) {
                // 击打声的包络线
                strikeEnvelope = Math.exp(-(time - 0.04) * 80);
            }

            // 组合所有成分
            double combined = (lowFreq + midFreq + highFreq + noise + highFreq2) * envelope + 
                             (noise * 2.0 + highFreq2 * 1.5) * strikeEnvelope;

            // 限制在有效范围内
            if (combined > 1.0) combined = 1.0;
            if (combined < -1.0) combined = -1.0;

            // 生成左右声道的样本值（相同值，创建单声道效果）
            short sampleValue = (short) (combined * Short.MAX_VALUE);

            // 限制样本值范围
            if (sampleValue > Short.MAX_VALUE) sampleValue = Short.MAX_VALUE;
            if (sampleValue < Short.MIN_VALUE) sampleValue = Short.MIN_VALUE;

            // 将short值转换为字节（小端序）
            // 左声道 (i*4 和 i*4+1)
            soundData[i * 4] = (byte) (sampleValue & 0xFF);
            soundData[i * 4 + 1] = (byte) ((sampleValue >> 8) & 0xFF);
            // 右声道 (i*4+2 和 i*4+3)
            soundData[i * 4 + 2] = (byte) (sampleValue & 0xFF);
            soundData[i * 4 + 3] = (byte) ((sampleValue >> 8) & 0xFF);
        }

        return soundData;
    }
}